package com.lsh.oms.core.service.sign;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.lsh.base.lang.Lists;
import com.lsh.oms.api.model.query.QuerySignDto;
import com.lsh.oms.api.model.shipping.ModifyDeliveryExtDto;
import com.lsh.oms.core.dao.other.OrderSignDetailMapper;
import com.lsh.oms.core.dao.other.OrderSignHeadMapper;
import com.lsh.oms.core.model.order.OrderSignDetail;
import com.lsh.oms.core.model.order.OrderSignHead;
import com.lsh.oms.core.service.sign.core.SignService;
import com.lsh.oms.core.service.tool.Criteria;
import com.lsh.oms.core.service.tool.Criterias;
import com.lsh.oms.core.service.tool.Pageable;
import com.lsh.oms.core.utils.DateUtil;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Component
public class SignServiceImpl implements SignService {

    @Resource
    private OrderSignHeadMapper mapper;

    @Resource
    private OrderSignDetailMapper detailMapper;

    @Override
    public Pageable<OrderSignHead> query(Criteria criteria, long page, long pageLimit) {
        Long count = mapper.countBaseOnCriteria(criteria);
        List<OrderSignHead> result = count > 0
                ? mapper.findBaseOnCriteria(criteria, Pageable.start(page, pageLimit), pageLimit)
                : Collections.emptyList();
        fillDetails(criteria, result);
        return new Pageable<>(result, page, pageLimit, count);
    }

    @Override
    public Optional<OrderSignHead> findById(Long id) {
        return findById(id, true);
    }

    @Override
    public Optional<OrderSignHead> findById(Long id, boolean detailsRequired) {
        Criteria criteria = new Criteria();
        criteria.add("details-required", String.valueOf(detailsRequired));
        return findById(id, criteria);
    }

    @Override
    public Optional<OrderSignHead> findById(Long id, Criteria criteria) {
        OrderSignHead receipt = mapper.selectByReceiptOrderId(id);
        if (receipt == null) {
            return Optional.empty();
        }
        if (Criterias.detailsRequired(criteria)) {
            receipt.setDetails(detailMapper.selectByReceiptOrderId(id));
        }
        return Optional.of(receipt);
    }

    private void fillDetails(Criteria criteria, List<OrderSignHead> heads) {
        if (Criterias.detailsRequired(criteria) && Lists.isNotEmpty(heads)) {
            Multimap<Long, OrderSignDetail> group = group(detailMapper.findDetailList(ids(heads)));
            for (OrderSignHead head : heads) {
                head.setDetails(new ArrayList<>(group.get(head.getReceiptOrderId())));
            }
        }
    }

    private Set<Long> ids(List<OrderSignHead> result) {
        Set<Long> ids = new HashSet<>();
        for (OrderSignHead item : result) {
            ids.add(item.getReceiptOrderId());
        }
        return ids;
    }

    private Multimap<Long, OrderSignDetail> group(List<OrderSignDetail> details) {
        Multimap<Long, OrderSignDetail> group = ArrayListMultimap.create();
        for (OrderSignDetail item : details) {
            group.put(item.getReceiptOrderId(), item);
        }
        return group;
    }

    @Override
    public Optional<OrderSignHead> findByOrderId(Long id) {
        return findByOrderId(id, true);
    }

    @Override
    public Optional<OrderSignHead> findByOrderId(Long id, boolean detailsRequired) {
        OrderSignHead head = mapper.selectByOrderCode(id);
        if (head == null) {
            return Optional.empty();
        }
        if (detailsRequired) {
            head.setDetails(detailMapper.selectByReceiptOrderId(head.getReceiptOrderId()));
        }
        return Optional.of(head);
    }

    @Override
    public Map<String, Long> findNumByParam(QuerySignDto querySignDto) {
        Map<String, Long> resmap = new HashMap<>();
        List<Integer> statuses = querySignDto.getStatuses();
        querySignDto.getRoute_ids().forEach((routeId) -> {

            QuerySignDto query = new QuerySignDto();

            query.setRoute_ids(Collections.singletonList(routeId));
            query.setStatuses(statuses);
            query.setPayStatus(querySignDto.getPayStatus());
            query.setIs_valid(1);
            Long totalCount = this.mapper.countByFilter(query);

            resmap.put(routeId.toString(), totalCount);
        });

        return resmap;
    }


    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Boolean updateOmsExt(ModifyDeliveryExtDto modifyDeliveryExtDto) {
        OrderSignHead orderSignHead = mapper.selectByReceiptOrderId(modifyDeliveryExtDto.getReceipt_order_id());
        if (null == orderSignHead) {
            return false;
        }

        OrderSignHead record = new OrderSignHead();
        record.setReceiptOrderId(modifyDeliveryExtDto.getReceipt_order_id());

        JSONArray imgList = new JSONArray();
//        imgList.addAll(modifyDeliveryExtDto.getProof_ids());
        modifyDeliveryExtDto.getProof_ids().forEach(img -> {
            imgList.add(img);
        });
        JSONObject proof_info = new JSONObject();
        proof_info.put("img_list", imgList);

        JSONObject omsext = JSON.parseObject(orderSignHead.getExt());

        omsext.put("proof_info", proof_info);
        omsext.put("proof_time", DateUtil.getCurrentTime());

        record.setExt(omsext.toJSONString());
        record.setUpdatedAt(DateUtil.getCurrentTime());

        return this.mapper.updateExtByReceiptOrderId(record) > 0;
    }



}
